// /**
//  * 方法装饰器
//  * 方法也区分静态和实例方法因此也分两种情况;
//  * 参数一：实例方法： 类的原型（对象类型）、静态方法：类本身（类构造函数类型）
//  * 参数二：字符串 方法名
//  * 参数三：属性描述对象 Object.defineProperty()中的属性描述对象{value:xxx, writable:xxx,enumerable:xxx,configurable:xxx};
//  */

// /**
//  * ---------------------- 方法装饰器 的 简单应用 ------------------------------
//  */
// // function d1(target: object, key: string, descriptor: PropertyDescriptor) {
// //   console.log(target, key, descriptor);
// // }
// // function d2(
// //   target: new (...args: any[]) => any,
// //   key: string,
// //   descriptor: PropertyDescriptor
// // ) {
// //   console.log(target, key, descriptor);
// // }

// // class A {
// //   prop1: string;
// //   static prop2: string;

// //   @d1
// //   method1() {}
// //   @d2
// //   static method2() {}
// // }

// /**
//  * ---------------------方法装饰器 的 工厂模式 方法装饰器的实际应用 -----------------
//  */
// function enumerable(str: string) {
//   return function (
//     target: object,
//     key: string,
//     descriptor: PropertyDescriptor
//   ) {
//     console.log(target, key, descriptor);
//     descriptor.enumerable = true;
//   };
// }

// /**
//  * 方法废弃装饰器
//  * @param target
//  * @param key
//  * @param descriptor
//  */
// function noUse(target: object, key: string, descriptor: PropertyDescriptor) {
//   descriptor.value = function () {
//     console.log("此方法已经被废弃");
//   };
// }
// /**
//  * 方法拦截装饰器
//  * @param target
//  * @param key
//  * @param descriptor
//  */
// function interceptor(str: string) {
//   return function (
//     target: object,
//     key: string,
//     descriptor: PropertyDescriptor
//   ) {
//     const tmp = descriptor.value;
//     descriptor.value = function (...args: any[]) {
//       console.log("前置拦截 ====", str);
//       tmp.call(this, ...args);
//     };
//   };
// }

// function d1(target: object, key: string, descriptor: PropertyDescriptor) {
//   console.log(target, key, descriptor);
// }
// function d2(target: object, key: string, descriptor: PropertyDescriptor) {
//   console.log(target, key, descriptor);
// }

// class A {
//   prop1: string;
//   prop2: string;

//   @enumerable("hello")
//   method1() {}
//   method2() {}
//   @interceptor("拦截method3")
//   method3(e: string) {
//     console.log("method3本来要执行的内容" + e);
//   }
// }
// const objA = new A();
// // 什么都打印不出来 prop1没有打印是因为 prop1没赋初始值编译的时候不认为这个有用就不生成了。

// console.log('遍历开始')
// for (let i in objA) {
//   console.log(i);
// }
// console.log('遍历结束')
// objA.method2();
// objA.method3("你好");

function Enumerable(str: string) {
  return function (
    target: object | (new (...args: any[]) => any),
    key: string,
    descriptor: PropertyDescriptor
  ) {
    descriptor.enumerable = true;
  };
}
// 废弃这个方法
function NoUse(
  target: object | (new (...args: any[]) => any),
  key: string,
  descriptor: PropertyDescriptor
) {
  descriptor.value = function () {
    console.log("这个方法已经被废弃了！");
  };
}
// 实现拦截器
function Interceptor_pre(
  target: object | (new (...args: any[]) => any),
  key: string,
  descriptor: PropertyDescriptor
) {
  const tmp = descriptor.value;
  descriptor.value = function (...args: any[]) {
    console.log("开始拦截");
    tmp.call(this, ...args);
    console.log("拦截结束");
  };
}

class A {
  prop1: string;
  @Enumerable("hello")
  method1() {}
  
  @Enumerable("method2")
  @NoUse
  method2() {}

  @Enumerable("method3")
  @Interceptor_pre
  method3(e: string) {
    console.log("i'm method III" + e);
  }
}
const a = new A();
a.method2();
a.method3("hello three");
console.log("开始遍历");
for (let i in a) {
  console.log(i);
}
